package com.wushijia.java8.lambda;

import static java.util.stream.Collectors.toList;

import com.wushijia.model.Shop;
import java.util.Arrays;
import java.util.List;
import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.stream.Collectors;

public class CompletableFutureDemo {

  public static void main(String[] args) {
    Shop shop = new Shop("BestShop");

    List<Shop> shopList = Arrays.asList(new Shop("BestPrice"),
        new Shop("LetSaveBig"),
        new Shop("MyFavoriteShop"),
        new Shop("BuyItAll"));
    //定制执行器
    final Executor executor = Executors.newFixedThreadPool(Math.min(shopList.size(), 100), new ThreadFactory() {
      @Override
      public Thread newThread(Runnable r) {
        Thread thread = new Thread(r);
        thread.setDaemon(true);
        return thread;
      }
    });

    TreeSet<String> treeSet = shopList.stream().map(Shop::getName).collect(Collectors.toCollection(TreeSet::new));
    System.out.println(Arrays.toString(treeSet.toArray()));

    System.out.println(shopList.stream().map(Object::toString).collect(Collectors.joining(",")));

    long start = System.nanoTime();
    Future<Double> futurePrice = shop.getPriceAsync("milk");
    long invocationTime = (System.nanoTime() - start) / 1_000_000;
    System.out.println("InvocationTime returned after " + invocationTime + " msecs");
    //执行更多任务，比如查询其他商店
    //doSomeThingElse();
    try {
      double price = futurePrice.get();
      System.out.printf("price is %.2f%n", price);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    long retrievalTime = (System.nanoTime() - start) / 1_000_000;
    System.out.println("price return after " + retrievalTime + " msece");

    long start2 = System.nanoTime();
    System.out.println(findPricesByExecutor(shopList, "myPhone", executor));
    long duration = (System.nanoTime() - start2) / 1_000_000;
    System.out.println("Done in " + duration + " msecs");


  }

  private static List<String> findPrices(List<Shop> shops, String productName) {
    return shops.stream().map(shop ->
        String.format("%s price is %s", shop.getName(), shop.getPrice(productName))).collect(toList());
  }

  //使用并行流
  private static List<String> findPricesByStream(List<Shop> shops, String productName) {
    return shops.parallelStream().map(shop ->
        String.format("%s price is %s", shop.getName(), shop.getPrice(productName))).collect(toList());
  }

  //使用CompletableFuture
  private static List<String> findPricesByCompletableFuture(List<Shop> shops, String productName) {
    List<CompletableFuture<String>> priceFutures = shops.stream()
        .map(shop -> CompletableFuture.supplyAsync(() -> String.format("%s price is %s", shop.getName(), shop.getPrice(productName)))
        ).collect(toList());
    //join：等待所有异步操作结束
    return priceFutures.stream().map(CompletableFuture::join).collect(toList());
  }

  //定制执行器
  private static List<String> findPricesByExecutor(List<Shop> shops, String productName, Executor executor) {
    List<CompletableFuture<String>> priceFutures = shops.stream()
        .map(shop -> CompletableFuture.supplyAsync(() -> String.format("%s price is %s", shop.getName(), shop.getPrice(productName)), executor)
        ).collect(toList());
    //join：等待所有异步操作结束，提取各自的返回值
    return priceFutures.stream().map(CompletableFuture::join).collect(toList());
  }


}
